當程式碼越寫越多的時候,尤其是要去開發大型專案,我們需要有組織的去管理程式碼,那看過前面文章的朋友應該知道,像是物件或是原型都沒有公開私有的概念,或許可以針對屬性集中管理,但是卻無法排除污染作用域的問題;此外,也因為沒有模組的概念,JS 無法將一個大專案拆分成許多互相依賴的小專案再將它組合起來(其他語言像是 python 都有 import 的功能)。
隔絕其他的文件,僅引用當前模組所需要的其他模組或是模組方法,就是模組化。
在 ES6 之前,有幾種常用的模組概念,我們先來介紹一下:
最早採用 CommonJS 標準之一的就是 Node.js,它有 4 個重要的變量支持著模組化這個概念,分別是 module
,export
, require
, global
。使用的時候,用 module.exports
輸出模組,需要的時候用 require
引入模組。CommonJS是用同步的方式加載模組,所以有時候速度會超慢....(阻塞)。
// 定義模組 calculate.js
var initial = 0;
function getSquareArea(width){
return Math.pow(width, 2);
}
module.exports = {
calculateArea: calculateArea,
initial : initial
}
// 引用自定義模組
var calculate = require('./calculate');
calculate.getSquareArea(5); // 25
// 引用核心模組
var http = require('http');
http.createService(...).listen(8888);
可以說是專門為瀏覽器中的 JS 環境設計的規範,最著名的就是 require.js,它是以異步的方式去加載模組,也比較符合瀏覽器的加載方式,但是最大的問題是一開始就會把所有相關的模組載入進來,不能按照需求加載。
// require([module],callback);
// example
require(['timer.js'],function(clock){
timer.start();
})
規範跟 AMD 很相像,主要差異在執行引用這件事時間點不一樣,開發者可以在需要用到模組實在 require,但是對於 JS 編輯器來說,需要先解析一遍才知道引用了哪些模組,雖然解析時間很短但卻會影響到性能。常見的套件像是 sea.js。
define(function(require,exports,module){
var timer = require('timer.js');
timer.start();
})
use strict
(嚴格模式)export
輸出, import
匯入可以將函式、物件甚至或是純值匯出,可區分為:
需要先將輸出值、表達式、函式、類別先賦予名稱才能匯出,import 也需要用所賦予的名稱才能引用
// export file
export const id = 1
export function getUserDetail(id, name, address) {
return `UserId: ${id}, Name: ${name}, Address: ${address}`
}
// import file
// 這裏的 as 是 重新命名
import { getUserDetail as renameGetUserDetail } from './module.js'
當輸出只有一個輸出值、表達式、函式、類別時,做為最低使用情況預設輸出時會加入default,一個檔案只能有一個
// 注意:一份檔案只會有一個 default export,這裡只是為了方便均寫在此
// export object file
export default {
id: 1,
name: 'Jacky',
method: function() {
console.log('call method');
},
}
// export function file
export default function() {
console.log('這是一段函式');
}
// export class file
export default class {
constructor(name) {
this.id = id;
}
getId() {
console.log(this.id);
}
}
// import object file
import object as defaultNamed from './module.js'
console.log(object.name) // Jacky
CommonJS 模組輸出的是值的緩存,沒有所謂的動態更新;而 ES6 的 export 輸出的是值的引用,所以會動態更新(例如在 call function 之後)
// module.js
let id = 1;
function changeId() {
id = 2;
}
module.exports = {
get id(){
return id
},
changeId: changeId,
};
//main.js
var main = require('./module.js')
console.log(main.id); // 1
main.changeId();
console.log(main.id); // 1
// module.js
export let id = 1;
export function changeId() {
id = 2;
}
//main.js
import {id,changeId} from './module.js'
console.log(id); // 1
changeId();
console.log(id); // 2